/*
 *
 * Copyright (c) 2023 - future
 * @author fzh
 * @email e_341877120_mail@163.com
 * @link https://mvnrepository.com/search?q=io.github.xrfzh.cn
 *
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package cn.xrfzh.common.utils;

import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

/**
 * 并行流工具类（提升批量插入大量数据（10w+ 甚至更高数据量）的性能）
 * <p>
 * 并行流 ：
 * <p>
 * 把一个内容分成多个数据块，并用不同的线程分 别处理每个数据块的流。 Java 8 中将并行进行了优化，我们可以很容易的对数据进行并行操作。Stream API
 * 可以声明性地通过 parallel() 与 sequential() 在并行流与顺序流之间进行切换。
 */
public class ParallelStreamUtil {

	/**
	 * 每个长SQL插入的行数，可以根据数据库性能调整
	 */
	private final static int SIZE = 1000;

	/**
	 * 如果需要调整并发数目，修改下面方法的第二个参数即可 并行流使用的并发数是CPU的核心数，不能局部更改，全局更改影响较大（慎重使用）
	 */
	static {
		System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "8");
	}

	/**
	 * 插入方法
	 * @param list 插入数据集合
	 * @param consumer 消费型方法，直接使用 mapper::method 方法引用的方式
	 * @param <T> 插入的数据类型
	 */
	public static <T> boolean insertBatchOfLarge(List<T> list, Consumer<List<T>> consumer) {
		if (ObjectUtils.isEmpty(list) || list.size() == 0) {
			return false;
		}
		try {
			List<List<T>> streamList = new ArrayList<>();
			for (int i = 0; i < list.size(); i += SIZE) {
				int j = Math.min((i + SIZE), list.size());
				List<T> subList = list.subList(i, j);
				streamList.add(subList);
			}
			streamList.parallelStream().forEach(consumer);
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		return true;
	}

}
